﻿using System;
using System.Data;
using System.Text;
using System.Globalization;

using BizElements.Core.ProviderComponents;

namespace BizElements.Core
{
    /// <summary>Extends <see cref="IDbTable"/> objects.</summary>
    public static class DbTableExtensions
    {
        /// <summary>Checks whether the two tables have equal aliases and names.</summary>
        /// <param name="table">Table whose name and alias are compared to other table..</param>
        /// <param name="otherTable">Other table.</param>
        /// <returns>True if aliases and names are equal. False otherwise.</returns>
        public static bool HasEqualAliasAndNameAs(this IDbTable table, IDbTable otherTable)
        {
            if (table.Alias == otherTable.Alias && table.TableName == otherTable.TableName)
                return true;
            else
                return false;
        } 

        /// <summary>Renders table name for the given DBMS. Handles special characters. </summary>
        /// <param name="table">Table whose name is to be rendered.</param>
        /// <param name="dbms">Target DBMS.</param>
        /// <param name="output">StringBuilder to which table name is appended.</param>
        /// <remarks>Special characters are handled differently on different DBMSs. 
        /// If table contains blanks it has to be enclosed in brackets for SQL Server 
        /// (eg. [My employees]), in quotes for Oracle (eg. "My employees") etc.</remarks>
        public static void RenderTableName(this IDbTable table, DbmsType dbms, StringBuilder output)
        {
            ITableRenderer renderer = DbmsComponentFactory.GetComponent<ITableRenderer>(dbms);
            renderer.RenderTableName(table, output);
        }

        /// <summary>Renders table alias for the given DBMS. Handles special characters.</summary>
        /// <param name="table">Table whose alias is to be rendered.</param>
        /// <param name="dbms">Target DBMS.</param>
        /// <param name="output">StringBuilder to which the alias is appended.</param>
        /// <remarks>Special characters are handled differently on different DBMSs. 
        /// If alias contains blanks it has to be enclosed in brackets for SQL Server 
        /// (eg. [My employees]), in quotes for Oracle (eg. "My employees") etc.</remarks>
        public static void RenderAlias(this IDbTable table, DbmsType dbms, StringBuilder output)
        {
            ITableRenderer renderer = DbmsComponentFactory.GetComponent<ITableRenderer>(dbms);
            renderer.RenderAlias(table, output);
        }

        /// <summary>Creates a new <see cref="DataTable"/> with all the columns and primary key defined by the IDbTable object.</summary>
        /// <returns>DataTable.</returns>
        /// <remarks><see cref="DataTable.TableName"/> property of the new DataTable must be equal to <see cref="DbTable.Alias"/> property of the current DbTable instance.</remarks>
        public static DataTable NewDataTable(this IDbTable table)
        {
            DataTable data = new DataTable();
            data.Locale = CultureInfo.InvariantCulture;

            if (table.Alias != null)
                data.TableName = table.Alias;
            else
                data.TableName = table.TableName;

            foreach (IDbColumn column in table.Columns)
                data.Columns.Add(column.NewDataColumn());

            var pkFields = table.PrimaryKey;
            DataColumn[] pk = new DataColumn[pkFields.Count];
            for (int pkFieldIdx = 0; pkFieldIdx < pkFields.Count; pkFieldIdx++)
                pk[pkFieldIdx] = data.Columns[pkFields[pkFieldIdx].ColumnName];

            data.PrimaryKey = pk;
            return data;
        }

        /// <summary>Creates a new <see cref="DataTable"/> with all the columns and primary key defined by the IDbTableConfiguration object.</summary>
        /// <returns>DataTable.</returns>
        internal static DataTable NewDataTable(IDbTableConfiguration tableConfig)
        {
            // This method is more expensive than NewDataTable(this IDbTable table).
            // Use this only to create prototype DataTable objects, i.e. when new DataTable object are created by cloning.
            DataTable data = new DataTable(tableConfig.TableName);
            data.Locale = CultureInfo.InvariantCulture;
            foreach (IDbColumnConfiguration colcfg in tableConfig.Columns)
            {
                SealedDbColumn col = new SealedDbColumn(colcfg, null);
                data.Columns.Add(col.NewDataColumn());
            }

            DataColumn[] pk = new DataColumn[tableConfig.PrimaryKeyColumnIndexes.Length];
            for (int partOrdinal = 0; partOrdinal < pk.Length; partOrdinal++)
            {
                int pkFieldIdx = tableConfig.PrimaryKeyColumnIndexes[partOrdinal];
                pk[partOrdinal] = data.Columns[pkFieldIdx];
            }

            data.PrimaryKey = pk;
            return data;
        }
    }
}
